﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WindowsInput;

namespace StrategicCommanderCenter
{
    public class ButtonArgs : EventArgs
    {
        public StrategicShiftState Shift;
        public StrategicButtons Button;

        public ButtonArgs(StrategicShiftState shift, StrategicButtons button)
        {
            this.Button = button;
            this.Shift = shift;
        }
    }

    public class AxisArgs : EventArgs
    {
        public int Value;
        public AxisArgs(int AxisValue)
        {
            this.Value = AxisValue;
        }
    }

    public delegate void AxisEvent(object sender, AxisArgs e);
    public delegate void ButtonPressEvent(object sender, ButtonArgs e);    
    public delegate void ButtonReleaseEvent(object sender, ButtonArgs e);

    public class EventShooter
    {
        private StrategicConfig config;
        private ReportDecoder decoder;

        public event AxisEvent XAxisChange;
        public event AxisEvent YAxisChange;
        public event AxisEvent RotAxisChange;
        public event ButtonPressEvent ButtonPress;
        public event ButtonReleaseEvent ButtonRelease;

        public bool FireProfileKeys;

        public EventShooter(ReportDecoder dec, StrategicConfig conf, bool Fire)
        {
            FireProfileKeys = Fire;
            decoder = dec;
            config = conf;
            dec.Changed += ChangedStateHandler;
        }

        private void ChangedStateHandler(object sender, ChangedStateArgs e)
        {
            StrategicShiftState shift = StrategicShiftState.None;
            StrategicProfileSelector prof = e.NewState.CurrentProfile;        

            //shifts
            for (int i = 0; i < 3; i++)
            {
                if (config.Profiles[(int)prof].ShiftAsModifier[i])
                {
                    if (e.NewState.ButtonStates[(int)StrategicButtons.Shift1])
                        shift = StrategicShiftState.Shift1;
                    else if (e.NewState.ButtonStates[(int)StrategicButtons.Shift2])
                        shift = StrategicShiftState.Shift2;
                    else if (e.NewState.ButtonStates[(int)StrategicButtons.Shift3])
                        shift = StrategicShiftState.Shift3;
                }
                else
                {
                    int shiftButton = i + 8;
                    if (CheckButtonPress(e.OldState.ButtonStates[shiftButton], e.NewState.ButtonStates[shiftButton]))
                    {
                        FireButtonPress(config.GetAssignedShifts((StrategicButtons)shiftButton, prof));
                        OnButtonPress( new ButtonArgs(shift, (StrategicButtons)shiftButton));
                    }
                    else if (CheckButtonRelease(e.OldState.ButtonStates[shiftButton], e.NewState.ButtonStates[shiftButton]))
                    {
                        FireButtonRelease(config.GetAssignedShifts((StrategicButtons)shiftButton, prof));
                        OnButtonRelease( new ButtonArgs(shift, (StrategicButtons)shiftButton));
                    }
                }
            }

            //buttons
            for (int i = 0; i < 8; i++)
            {
                if (CheckButtonPress(e.OldState.ButtonStates[i], e.NewState.ButtonStates[i]))
                {
                    FireButtonPress(config.GetAssignedButtons((StrategicButtons)i, shift, prof));
                    OnButtonPress(new ButtonArgs(shift, (StrategicButtons)i));
                }
                else if (CheckButtonRelease(e.OldState.ButtonStates[i], e.NewState.ButtonStates[i]))
                {
                    FireButtonRelease(config.GetAssignedButtons((StrategicButtons)i, shift, prof));
                    OnButtonRelease( new ButtonArgs(shift, (StrategicButtons)i));
                }
            }          

            //Rec button              
            if (CheckButtonPress(e.OldState.ButtonStates[11], e.NewState.ButtonStates[11]))
            {
                FireButtonPress(config.GetAssignedButtons(StrategicButtons.Rec, shift, prof));
                OnButtonPress(new ButtonArgs(shift, StrategicButtons.Rec));
            }
            else if (CheckButtonRelease(e.OldState.ButtonStates[11], e.NewState.ButtonStates[11]))
            {
                FireButtonRelease(config.GetAssignedButtons(StrategicButtons.Rec, shift, prof));
                OnButtonRelease(new ButtonArgs(shift, StrategicButtons.Rec));
            }
            
            //Axis
            if (e.OldState.XAxis != e.NewState.XAxis)
            {
                OnXAxisChange(new AxisArgs(e.NewState.XAxis));
                if ((Math.Abs(e.OldState.XAxis) < config.XDeadZone) && (Math.Abs(e.NewState.XAxis) >= config.XDeadZone))
                {
                    if (e.NewState.XAxis < 0)
                        FireButtonPress(config.GetAssignedLeft(prof));
                    else
                        FireButtonPress(config.GetAssignedRight(prof));
                } 
                else if ((Math.Abs(e.OldState.XAxis) >= config.XDeadZone) && (Math.Abs(e.NewState.XAxis) < config.XDeadZone))
                {
                    if (e.OldState.XAxis < 0)
                        FireButtonRelease(config.GetAssignedLeft(prof));
                    else
                        FireButtonRelease(config.GetAssignedRight(prof));
                }
            }

            if (e.OldState.YAxis != e.NewState.YAxis)
            {
                OnYAxisChange(new AxisArgs(e.NewState.YAxis)); 
                if ((Math.Abs(e.OldState.YAxis) < config.YDeadZone) && (Math.Abs(e.NewState.YAxis) >= config.XDeadZone))
                {
                    if (e.NewState.YAxis < 0)
                        FireButtonPress(config.GetAssignedUp(prof));
                    else
                        FireButtonPress(config.GetAssignedDown(prof));
                }
                else if ((Math.Abs(e.OldState.YAxis) >= config.YDeadZone) && (Math.Abs(e.NewState.YAxis) < config.XDeadZone))
                {
                    if (e.OldState.YAxis < 0)
                        FireButtonRelease(config.GetAssignedUp(prof));
                    else
                        FireButtonRelease(config.GetAssignedDown(prof));
                }
            }

            if (e.OldState.Rotation != e.NewState.Rotation)
            {
                OnRotAxisChange(new AxisArgs(e.NewState.Rotation));
                if ((Math.Abs(e.OldState.Rotation) < config.RotDeadZone) && (Math.Abs(e.NewState.Rotation) >= config.RotDeadZone))
                {
                    if (e.NewState.Rotation < 0)
                        FireButtonPress(config.GetAssignedRotateLeft(prof));
                    else
                        FireButtonPress(config.GetAssignedRotateRight(prof));
                }
                else if ((Math.Abs(e.OldState.Rotation) >= config.RotDeadZone) && (Math.Abs(e.NewState.Rotation) < config.RotDeadZone))
                {
                    if (e.OldState.Rotation < 0)
                        FireButtonRelease(config.GetAssignedRotateLeft(prof));
                    else
                        FireButtonRelease(config.GetAssignedRotateRight(prof));
                }
            }
        }

        protected void OnXAxisChange(AxisArgs e)
        {
            if (XAxisChange != null)
                XAxisChange(this, e);
        }

        protected void OnYAxisChange(AxisArgs e)
        {
            if (YAxisChange != null)
                YAxisChange(this, e);
        }

        protected void OnRotAxisChange(AxisArgs e)
        {
            if (RotAxisChange != null)
                RotAxisChange(this, e);
        }

        protected void OnButtonPress(ButtonArgs e)
        {
            if (ButtonPress != null)
                ButtonPress(this, e);
        }

        protected void OnButtonRelease(ButtonArgs e)
        {
            if (ButtonRelease != null)
                ButtonRelease(this, e);
        }

        private bool CheckButtonPress(bool oldstate, bool newState)
        {
            return ((oldstate == false) && (newState == true));
        }

        private bool CheckButtonRelease(bool oldstate, bool newState)
        {
            return ((oldstate == true) && (newState == false));
        }

        private void FireButtonPress(StrategicAssignment action)
        {
            if (FireProfileKeys)
            {
                foreach (VirtualKeyCode vk in action.Codes)
                {
                    //TODO: Da usare tramite MapVirtualKey per usare gli scancode?
                    InputSimulator.SimulateKeyDown(vk);
                }
            }
        }

        private void FireButtonRelease(StrategicAssignment action)
        {
            if (FireProfileKeys)
            {
                foreach (VirtualKeyCode vk in action.Codes)
                {
                    //TODO: Da usare tramite MapVirtualKey per usare gli scancode?
                    InputSimulator.SimulateKeyUp(vk);
                }
            }
        }
    }
}
